package com.yeyks.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.sun.org.apache.xpath.internal.operations.Bool;
import com.yeyks.base.Arguments;
import com.yeyks.constant.MessageTemplate;
import com.yeyks.dal.dao.CouponInfoMapper;
import com.yeyks.dal.dao.UserCouponInfoMapper;
import com.yeyks.dal.dao.UserInfoMapper;
import com.yeyks.dal.domain.*;
import com.yeyks.dto.BankBindDTO;
import com.yeyks.exception.ServiceException;
import com.yeyks.model.CouponConst;
import com.yeyks.service.*;
import com.yeyks.util.DateUtils;
import com.yeyks.dal.domain.VipInfo;
import com.yeyks.exception.ServiceException;
import com.yeyks.model.CouponConst;
import com.yeyks.service.SmsService;
import com.yeyks.service.TokenService;
import com.yeyks.service.UserInfoService;
import com.yeyks.service.VipInfoService;
import com.yeyks.util.DateUtils;
import com.yeyks.util.FormatUtils;
import com.yeyks.util.InvateCode;
import com.yeyks.wxcode.service.WxLoginService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Author fuchangshuai
 * @date 2019/2/25 7:51 PM
 */
@Slf4j
@Transactional
@Service
public class UserInfoServiceImpl implements UserInfoService {

    @Autowired
    private VipInfoService vipInfoService;
    @Autowired
    private UserInfoMapper userInfoMapper;
    @Autowired
    private CouponInfoMapper couponInfoMapper;
    @Autowired
    private UserCouponInfoMapper userCouponInfoMapper;
    @Autowired
    private UserCouponService userCouponService;
    @Autowired
    private SmsService smsService;
    @Autowired
    private TokenService tokenService;
    @Autowired
    private MessageNoticeService noticeService;
    @Autowired
    private MessageNoticeTemplateService templateService;
    @Autowired
    private WxLoginService wxLoginService;

    /**
     * 用户充值10元成普通vip会员，得两张50元券
     *
     * @param id
     * @param payAmount
     * @return
     */
    @Override
    @Transactional
    public Boolean createVIP(Integer id, Integer payAmount) {

        //通过付款金额查询对应的有效的vip券
        CouponInfo couponInfo = couponInfoMapper.selectCouponByPayAmount(payAmount);
        if (couponInfo == null) {
            log.info("通过付款数获取不到对应的vip券{}", payAmount);
            return false;
        }
        if (couponInfo.getRemainCount() == null || couponInfo.getRemainCount() <= 0) {
            log.info("分享有礼券剩余数量为空");
            return false;
        }
        UserCouponInfo userCouponInfo = getUserCouponInfo(id, couponInfo.getId(), couponInfo.getDuration());
        for (int i = 0; i < 2; i++) {
            userCouponInfoMapper.insertReturnId(userCouponInfo);
        }
        //充值成功消息记录
        payMessageNotice(id, payAmount, couponInfo.getPrice(), 2);
        userCouponService.updateCount(2, couponInfo);
        //查询用户，并修改该用户为vip
        UserInfo userInfo = userInfoMapper.selectByPrimaryKey(id);
        userInfo.setIsVip(1);
        userInfoMapper.updateByPrimaryKey(userInfo);
        return true;
    }

    private void payMessageNotice(Integer userId, Integer payAmount, Integer price, int count) {
        try {
            String payAmountStr = FormatUtils.fenToYuan(payAmount);
            String amount = FormatUtils.fenToYuan(price);
            Map<String, Object> params = new HashMap<>();
            params.put("payAmount", payAmountStr);
            params.put("amount", amount);
            params.put("count", count);
            Map<String, String> map = templateService.commonValue(params, MessageTemplate.PAY_COUPON);
            noticeService.activieyCreateAndSave(map, userId, MessageNotice.Type.activity_coupon.value());
        } catch (Exception e) {
            log.error("分享充值消息写入异常{}", e.getLocalizedMessage());
            e.printStackTrace();
        }
    }

    /**
     * 通过手机号查询用户信息
     *
     * @param phone
     * @return
     */
    @Override
    public UserInfo selectUseInfoPhone(String phone) {
        return userInfoMapper.selectUseInfoPhone(phone);
    }

    /**
     * 用户设置头像
     *
     * @param id
     * @param avatar
     * @return
     */
    @Override
    public Integer updateAvatar(Integer id, String avatar) {
        return userInfoMapper.updateAvatar(id, avatar);
    }

    /**
     * 增加用户，并返回用户id
     *
     * @param userInfo
     */
    @Override
    public void insertReturnId(UserInfo userInfo) {
        userInfoMapper.insertReturnId(userInfo);
    }

    /**
     * 通过用户id，修改用户密码
     *
     * @param id
     * @param password
     * @return
     */
    @Override
    public Integer modifyPasswordById(Integer id, String password) {
        return userInfoMapper.modifyPasswordById(id, password);
    }

    /**
     * 通过用户id查询用户
     *
     * @param id
     * @return
     */
    @Override
    public UserInfo selectByPrimaryKey(Integer id) {
        return userInfoMapper.selectByPrimaryKey(id);
    }

    /**
     * 分享后用户通过手机号注册
     *
     * @param userInfo
     */
    @Transactional
    @Override
    public Boolean phoneLogin(UserInfo userInfo) {
        //保存用户的信息
        userInfoMapper.insertReturnId(userInfo);
        if (userInfo.getId() != null) {
            userInfo.setInviteCode(InvateCode.toSerialCode(userInfo.getId()));
            int res = updateUserInfo(userInfo);
            if (res != 1) {
                log.info("更新邀请码异常");
            }
            //给新人发两张10元新人券
            userCouponService.createNewCoupon(userInfo.getId());
        }
        //给注册用户发送短信，内容为自己密码
        if (!smsService.sendPwcSms(userInfo.getPhone(), userInfo.getPassword())) {
            log.info("给注册用户发送短信失败");
        }
        //给分享人发一张10元分享有礼券
        Integer price = 1000;
        CouponInfo couponInfo = couponInfoMapper.selectShareCouponByTypePrice(CouponConst.typeShare, price);
        if (couponInfo == null) {
            log.info("分享有礼券不存在");
            return false;
        }
        if (couponInfo.getRemainCount() == null || couponInfo.getRemainCount() <= 0) {
            log.info("分享有礼券剩余数量为空");
            return false;
        }
        UserInfo shareUserInfo = userInfoMapper.selectByPrimaryKey(userInfo.getParentId());
        if (shareUserInfo == null) {
            log.info("通过分享人id查询不到该用户{}", userInfo.getParentId());
            return false;
        }
        UserCouponInfo userCouponInfo = getUserCouponInfo(shareUserInfo.getId(), couponInfo.getId(), couponInfo.getDuration());
        userCouponInfoMapper.insertReturnId(userCouponInfo);
        messageNotice(userInfo.getPhone(), couponInfo.getPrice(), 1, userInfo.getParentId());
        userCouponService.updateCount(1, couponInfo);
        return true;

    }

    private void messageNotice(String phone, Integer price, int count, Integer userId) {
        try {
            String amount = FormatUtils.fenToYuan(price);
            Map<String, Object> params = new HashMap<>();
            params.put("phone", phone);
            params.put("amount", amount);
            params.put("count", count);
            Map<String, String> map = templateService.commonValue(params, MessageTemplate.INVATE_COUPON);
            noticeService.activieyCreateAndSave(map, userId, MessageNotice.Type.activity_coupon.value());
        } catch (Exception e) {
            log.error("分享有礼消息写入异常{}", e.getLocalizedMessage());
            e.printStackTrace();
        }
    }

    /**
     * 通过用户的id更新扩展字段
     *
     * @param id
     * @param extraInfo
     * @return
     */
    @Override
    public Integer updateExtraInfoById(Integer id, String extraInfo) {
        return userInfoMapper.updateExtraInfoById(id, extraInfo);
    }

    private VipInfo getVipInfo(Integer id, Integer payAmount) {
        VipInfo vipInfo = new VipInfo();
        vipInfo.setPayAmount(payAmount);
        vipInfo.setUserId(id);
        vipInfo.setStatus(1);
        vipInfo.setType(1);
        return vipInfo;
    }

    private UserCouponInfo getUserCouponInfo(Integer userId, Integer couponId, Integer duration) {
        UserCouponInfo userCouponInfo = new UserCouponInfo();
        userCouponInfo.setCouponId(couponId);
        userCouponInfo.setUserId(userId);
        userCouponInfo.setUsed(false);
        if (duration == null || duration == 0) {
            //180天
            duration = 180;
        }
        Date date = DateUtils.afterDaysToDate(new Date(), Long.valueOf(duration));
        userCouponInfo.setOverTime(date);
        return userCouponInfo;
    }

    /**
     * 通过用户id获取token
     *
     * @param userId
     * @return
     */
    @Override
    public String getTokenByUseId(Integer userId) {
        return tokenService.createToken(String.valueOf(userId));
    }

    /**
     * 通过token获取用户信息
     *
     * @param token
     * @return
     */
    @Override
    public UserInfo tokenUserInfo(String token) {
        UserInfo userInfo = null;
        try {
            String userId = tokenService.getUserId(token);
            userInfo = userInfoMapper.selectByPrimaryKey(Integer.valueOf(userId));
        } catch (ServiceException e) {
            throw new ServiceException(e.getCode(), e.getMessage());
        } catch (Exception e) {
            log.info("通过用户token获取用户失败，token=" + token + "，错误信息：" + e.getMessage());
        }
        if (userInfo == null) {
            log.info("该用户不存在，token={}", token);
            throw new ServiceException("该用户不存在");
        }
        return userInfo;
    }

    /**
     * 通过邀请码获取该用户是否存在
     *
     * @param code
     * @return
     */
    @Override
    public UserInfo selectUserByCode(String code) {
        return userInfoMapper.selectUserByCode(code);

    }

    @Override
    public int updateUserInfo(UserInfo userInfo) {
        return userInfoMapper.updateByPrimaryKey(userInfo);
    }

    /**
     * test给用户生成邀请码
     */
    @Override
    public void createCode() {
        List<UserInfo> userInfos = userInfoMapper.selectAll();
        for (UserInfo userInfo : userInfos) {
            if (userInfo.getInviteCode() == null || userInfo.getInviteCode().length() > 6) {
                String code = InvateCode.toSerialCode(userInfo.getId());
                userInfo.setInviteCode(code);
                userInfoMapper.updateByPrimaryKey(userInfo);
            }
        }
    }

    /**
     * 获取用户openid
     *
     * @param userInfo
     * @param code 微信code
     * @param type 类型gzh(公众号),xcx(小程序)
     * @return
     */
    @Override
    public String getOpenId(UserInfo userInfo, String code, String type) {
        //true代表是公众号，false代表小程序
        boolean flag = true;
        if (type.equals("xcx")) {
            flag = false;
        }
        JSONObject jsonObject = JSONObject.parseObject(userInfo.getExtraInfo());
        //公众号
        if (flag) {
            String gzhOpenId = null;
            if (jsonObject != null) {
                gzhOpenId = (String) jsonObject.get("gzhOpenId");
            }
            if (gzhOpenId != null) {
                return gzhOpenId;
            }
            if (!Arguments.notEmpty(code)) {
                throw new ServiceException("openid为空");
            }
            gzhOpenId = wxLoginService.getOpenId(code, type);
            Map<String, Object> map = new HashMap<>();
            map.put("gzhOpenId", gzhOpenId);
            if (jsonObject != null) {
                String xcxOpenId = (String) jsonObject.get("xcxOpenId");
                if (Arguments.notEmpty(xcxOpenId)) {
                    map.put("xcxOpenId", xcxOpenId);
                }
            }
            userInfo.setExtraInfo(JSONObject.toJSONString(map));
            Integer res = userInfoMapper.updateExtraInfoById(userInfo.getId(), userInfo.getExtraInfo());
            if (res != 1) {
                throw new ServiceException("更新openid失败");
            }
            return gzhOpenId;
        }
        //小程序
        String xcxOpenId = null;
        if (jsonObject != null) {
            xcxOpenId = (String) jsonObject.get("xcxOpenId");
        }
        if (xcxOpenId != null) {
            return xcxOpenId;
        }
        if (!Arguments.notEmpty(code)) {
            throw new ServiceException("openid为空");
        }
        xcxOpenId = wxLoginService.getOpenId(code, type);
        Map<String, Object> map = new HashMap<>();
        map.put("xcxOpenId", xcxOpenId);
        if (jsonObject != null) {
            String gzhOpenId = (String) jsonObject.get("gzhOpenId");
            if (Arguments.notEmpty(gzhOpenId)) {
                map.put("gzhOpenId", gzhOpenId);
            }
        }
        userInfo.setExtraInfo(JSONObject.toJSONString(map));
        Integer res = userInfoMapper.updateExtraInfoById(userInfo.getId(), userInfo.getExtraInfo());
        if (res != 1) {
            throw new ServiceException("更新openid失败");
        }
        return xcxOpenId;
    }

    /**
     * 判断用户是否需要绑卡
     *
     * @param userInfo
     * @return
     */
    @Override
    public Boolean isBind(UserInfo userInfo) {
        boolean flag = false;
        try {
            String payAccount = userInfo.getPayAccount();
            if (payAccount == null) {
                flag = true;
            }
        } catch (Exception e) {
            log.error("判断用户是否需要绑卡异常{}", e.getLocalizedMessage());
            e.printStackTrace();
            flag = true;
        }
        return flag;
    }

    /**
     * 用户绑定银行卡
     *
     * @param userInfo
     * @param bankCard
     * @param bankName
     * @param userName
     * @return
     */
    @Override
    public Boolean bankCard(UserInfo userInfo, String bankCard, String bankName, String userName) {
        try {
            Map<String, String> map = new HashMap<>();
            map.put("bankCard", bankCard);
            map.put("bankName", bankName);
            map.put("userName", userName);
            userInfo.setPayAccount(JSONObject.toJSONString(map));
            return userInfoMapper.updateByPrimaryKey(userInfo) == 1;
        } catch (Exception e) {
            log.error("用户绑定银行卡异常{}", e.getLocalizedMessage());
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 获取用户绑卡信息
     *
     * @param userInfo
     * @return
     */
    @Override
    public BankBindDTO bankCardInfo(UserInfo userInfo) {
        BankBindDTO bankBindDTO = new BankBindDTO();
        String payAccount = userInfo.getPayAccount();
        if (Arguments.notEmpty(payAccount)) {
            JSONObject jsonObject = JSONObject.parseObject(payAccount);
            bankBindDTO.setBankCard((String) jsonObject.get("bankCard"));
            bankBindDTO.setBankName((String) jsonObject.get("bankName"));
            bankBindDTO.setUserName((String) jsonObject.get("userName"));
            return bankBindDTO;
        }
        log.info("该用户并未绑卡userId = {}", userInfo.getId());
        return bankBindDTO;
    }
}
